using System;
using System.Collections;
using NFreeMarker.Ext.Util;
using NFreeMarker.Template;

namespace NFreeMarker.Ext.Beans
{
    /**
     * <p>A special case of {@link BeanModel} that can wrap Java collections
     * and that implements the {@link TemplateCollectionModel} in order to be usable 
     * in a <tt>&lt;foreach></tt> block.</p>
     * @author Attila Szegedi
     * @version $Id: CollectionModel.java,v 1.22 2003/06/03 13:21:32 szegedia Exp $
     */
    public class CollectionModel : StringModel, ITemplateCollectionModel, ITemplateSequenceModel
    {
        internal static readonly IModelFactory Factory = new ModelFactoryImpl();

        private class ModelFactoryImpl : IModelFactory
        {
            public ITemplateModel Create(object obj, IObjectWrapper wrapper)
            {
                return new CollectionModel((ICollection) obj, (BeansWrapper)wrapper);
            }
        }

        /**
         * Creates a new model that wraps the specified collection object.
         * @param collection the collection object to wrap into a model.
         * @param wrapper the {@link BeansWrapper} associated with this model.
         * Every model has to have an associated {@link BeansWrapper} instance. The
         * model gains many attributes from its wrapper, including the caching 
         * behavior, method exposure level, method-over-item shadowing policy etc.
         */
        public CollectionModel(ICollection collection, BeansWrapper wrapper)
            : base(collection, wrapper)
        {
        }

        /**
         * Retrieves the i-th object from the collection, wrapped as a TemplateModel.
         * @throws TemplateModelException if the index is out of bounds, or the
         * underlying collection is not a List.
         */
        public ITemplateModel Get(int index)
        {
            if (Object is IList)
            {
                try
                {
                    return Wrap(((IList) Object)[index]);
                }
                catch (IndexOutOfRangeException)
                {
                    return null;
    //                throw new TemplateModelException("Index out of bounds: " + index);
                }
            }
            else
            {
                throw new TemplateModelException("Underlying collection is not a list, it's " + Object.GetType().FullName);
            }
        }
        
        public ITemplateModelIterator Iterator()
        {
            return new IteratorModel(((ICollection) Object).GetEnumerator(), Wrapper);
        }

        public override int Size()
        {
            return ((ICollection) Object).Count;
        }
    }
}